// Geometric Tools, Inc.
// http://www.geometrictools.com
// Copyright (c) 1998-2006.  All Rights Reserved
//
// The Wild Magic Version 4 Restricted Libraries source code is supplied
// under the terms of the license agreement
//     http://www.geometrictools.com/License/Wm4RestrictedLicense.pdf
// and may not be copied or disclosed except in accordance with the terms
// of that agreement.

#ifndef WM4MASSSPRINGARBITRARY_H
#define WM4MASSSPRINGARBITRARY_H

#include "Wm4PhysicsLIB.h"
#include "Wm4ParticleSystem.h"

namespace Wm4
{

template <class Real, class TVector>
class WM4_PHYSICS_ITEM MassSpringArbitrary
    : public ParticleSystem<Real,TVector>
{
public:
    // Construction and destruction.  This class represents a set of M
    // masses that are connected by S springs with arbitrary topology.  The
    // function SetSpring(...) should be called for each spring that you
    // want in the system.
    MassSpringArbitrary (int iNumParticles, int iNumSprings, Real fStep);
    virtual ~MassSpringArbitrary ();

    int GetNumSprings () const;
    void SetSpring (int iSpring, int iParticle0, int iParticle1,
        Real fConstant, Real fLength);
    void GetSpring (int iSpring, int& riParticle0, int& riParticle1,
        Real& rfConstant, Real& rfLength) const;

    Real& Constant (int iSpring);
    Real& Length (int iSpring);

    // Callback for acceleration (ODE solver uses x" = F/m) applied to
    // particle i.  The positions and velocities are not necessarily
    // m_akPosition and m_akVelocity since the ODE solver evaluates the
    // impulse function at intermediate positions.
    virtual TVector Acceleration (int i, Real fTime,
        const TVector* akPosition, const TVector* akVelocity);

    // The default external force is zero.  Derive a class from this one to
    // provide nonzero external forces such as gravity, wind, friction,
    // and so on.  This function is called by Acceleration(...) to append the
    // acceleration F/m generated by the external force F.
    virtual TVector ExternalAcceleration (int i, Real fTime,
        const TVector* akPosition, const TVector* akVelocity);

protected:
    using ParticleSystem<Real,TVector>::m_iNumParticles;
    using ParticleSystem<Real,TVector>::m_afInvMass;

    class WM4_PHYSICS_ITEM Spring
    {
    public:
        int Particle0, Particle1;
        Real Constant, Length;
    };

    int m_iNumSprings;
    Spring* m_akSpring;

    // Each particle has an associated array of spring indices for those
    // springs adjacent to the particle.  The set elements are spring
    // indices, not indices of adjacent particles.
    std::set<int>* m_akAdjacent;
};

typedef MassSpringArbitrary<float,Vector2f> MassSpringArbitrary2f;
typedef MassSpringArbitrary<double,Vector2d> MassSpringArbitrary2d;
typedef MassSpringArbitrary<float,Vector3f> MassSpringArbitrary3f;
typedef MassSpringArbitrary<double,Vector3d> MassSpringArbitrary3d;

}

#endif
